<template>
  <div class="gantt-table">
    <header>
      <slot name="header"></slot>
    </header>
    <div ref="treeContainer" class="table-container" @scroll="onScroll">
      <!-- :span-method="objectSpanMethod" -->
      <el-table
        ref="tree"
        :data="treeData"
        style="width: 100%;"
        row-key="id"
        default-expand-all
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
        @row-click="onNodeClick"
        v-bind="treeAttrs"
        :highlight-current-row="true"
      >
        <el-table-column
          v-for="item in columns"
          :prop="item.code"
          :label="item.label"
          :width="item.width"
          :key="item.code"
        >
        </el-table-column>
      </el-table>
    </div>
  </div>
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import {
  BaseItem,
  GanttData,
  GanttNode,
  TableColumnList,
  GanttItem,
  Bus,
  BaseMilestone,
} from '@/utils/types';
import { isGroup, search, isMilestone } from '@/utils';

// REVIEW: 可能要抽离 Milestone 节点类型，才好进一步拓展功能
interface TreeNode extends BaseItem {
  progress?: GanttItem['progress'];
  done?: BaseMilestone['done'];
  children?: TreeNode[];
}

interface ElTreeNode {
  data: TreeNode;
}

function transform(item: GanttNode): TreeNode {
  const base = {
    id: item.id,
    name: item.name,
    date: item.date,
    no: item.no,
    code: item.code,
    unit: item.unit,
    wbsCode: item.wbsCode,
    node: item.node,
    syncProgress: item.syncProgress,
    status: item.status,
    startDate: item.startDate,
    endDate: item.endDate,
  };
  if (isGroup(item)) {
    return {
      ...base,
      progress: item.progress,
      children: item.children.map(transform),
    };
  } else if (isMilestone(item)) {
    return {
      ...base,
      done: item.done,
    };
  } else {
    return {
      progress: item.progress,
      ...base,
    };
  }
}

export default Vue.extend({
  name: 'GanttTable',
  props: {
    bus: {
      type: Object as PropType<Bus>,
      required: true,
    },
    data: {
      type: Array as PropType<GanttData>,
      required: true,
    },
    // TODO
    scrollTop: {
      type: Number,
      required: true,
    },
    treeAttrs: {
      type: Object,
      default: () => ({}),
    },
    dragData: {
      type: Object as PropType<{ node: GanttNode | null; movedCols: number }>,
      required: true,
    },
    /**
     * 表格列
     */
    columns: {
      type: Array as PropType<TableColumnList>,
      required: true,
    },
  },
  data: () => ({
    dragging: false,
  }),
  computed: {
    treeData(): TreeNode[] {
      return this.data.map(transform);
    },
  },
  watch: {
    'dragData.node': {
      // FIXME： 需要处理反向选中
      // (this.$refs.treeContainer as HTMLElement).scrollTo(0, v);
      handler(v) {
        console.log(v, this.$refs.tree);
        // this.$refs.tree.setCurrentRow({
        //   id: 'item-1',
        //   name: '叶节点-1',
        //   progress: 30,
        //   startDate: '2023-02-16',
        //   endDate: '2023-02-17',
        //   date: '2023-02-16',
        // });
        // this.$refs.tree.setCurrentRow(v, true);
      },
      immediate: false,
    },
    treeData: {
      handler() {
        /**
         * 手动控制内部节点的展开状态；default-expanded-keys 很难用
         * @see https://blog.csdn.net/gaojie_csdn/article/details/80738488
         */
        this.$nextTick(() => {
          const { nodesMap } = (this.$refs.tree as any).store;
          for (const k in nodesMap) {
            nodesMap[k].expanded = !this.bus.collapsedMap[k];
          }
        });
      },
      immediate: true,
    },
  },
  methods: {
    // 表格行合并
    // objectSpanMethod({ row, column, rowIndex, columnIndex }) {
    // TODO 需要单独处理逻辑
    // if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) {
    //   if (rowIndex % 2 === 0) {
    //     return {
    //       rowspan: 2,
    //       colspan: 1,
    //     };
    //   } else {
    //     return {
    //       rowspan: 0,
    //       colspan: 0,
    //     };
    //   }
    // }
    // },
    isMilestone,
    onNodeExpand(node: TreeNode) {
      this.expandData(node);
    },
    onNodeCollapse(node: TreeNode) {
      this.expandData(node, false);
    },
    expandData(node: TreeNode, expand = true) {
      this.bus.collapsedMap[node.id] = !expand;
    },
    onDelete(node: TreeNode) {
      // @ts-ignore
      this.$confirm(`确定删除“${node.name}”？`, '提示', {
        type: 'warning',
        beforeClose: (action: string, instance: any, done: Function) => {
          if (action !== 'confirm') return done();
          instance.confirmButtonLoading = true;
          const callback = () => {
            instance.confirmButtonLoading = false;
            done();
          };
          this.$emit('delete', {
            id: node.id,
            done: callback,
          });
        },
      }).catch(() => {});
    },
    /**
     * 调用时，treeData 已经变更了
     */
    onDrop(
      draggingNode: ElTreeNode,
      _dropNode: ElTreeNode,
      dropType: 'inner' | 'after' | 'before',
    ) {
      this.dragging = true;
      const done = () => (this.dragging = false);
      // REVIEW: 其实处理方式是一样的，先观望一下再移除 switch 代码
      switch (dropType) {
        case 'inner':
        case 'before':
        case 'after':
          this.notifyMovement(draggingNode.data.id, done);
          break;
      }
    },
    notifyMovement(id: GanttNode['id'], done: Function) {
      const [node, parent] = search(id, this.treeData) as [TreeNode, TreeNode?];
      const index = (parent ? parent.children! : this.treeData).indexOf(node);
      // console.log(node, oldParent, parent)
      this.$emit('move', {
        id: node.id,
        pid: parent ? parent.id : undefined,
        index,
        done,
      });
    },
    onScroll(e: { target: HTMLElement }) {
      this.$emit('update:scrollTop', e.target.scrollTop);
    },
    onNodeClick(node: TreeNode) {
      console.log(this.bus, 'node....');

      const { ee } = this.bus;
      ee.emit(ee.Event.ScrollToNode, node.id);
    },
  },
});
</script>
<style lang="less" scoped>
@import '../assets/vars';

.gantt-table {
  display: flex;
  flex-direction: column;
  width: 50%;

  header {
    max-height: @header-height;
    display: flex;
    padding: 0 5px;
  }

  .table-container {
    overflow-x: scroll; // 与 chart 下边对齐
    overflow-y: auto;
    padding: 0 2px 20px 0;

    .tree-node {
      flex: 1 1 auto;
      display: flex;
      align-items: center;
      min-width: 0; // make ellipsis work in grid item
      padding-right: 5px;

      .milestone-mark {
        margin-right: 4px;
        width: 8px;
        height: 8px;
        transform: rotate(45deg);
        border: 1.5px solid @progress-content;
        border-radius: 2px;

        &.done {
          border-color: @done;
        }
      }

      .name {
        margin-right: 5px;
      }

      .progress {
        margin-left: auto;
      }

      .delete {
        margin-left: 5px;
      }
    }
  }

  /deep/ .el-tree-node__content {
    height: 30px; // FIXME: 使用 rowH
  }
}
</style>
